﻿using System;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using System.IO.Pipelines;
using System.Buffers;
using System.Net;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Linq;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using System.Text;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections;

namespace JTActiveSafety.Gateway.Internal
{
    internal sealed class SocketConnectionListener : IConnectionListener
    {
        private readonly MemoryPool<byte> _memoryPool;
        private readonly int _numSchedulers;
        private readonly PipeScheduler[] _schedulers;
        private readonly ISocketsTrace _trace;
        private Socket _listenSocket;
        private int _schedulerIndex;
        private readonly SocketTransportOptions _options;
        private SafeSocketHandle _socketHandle;

        public EndPoint EndPoint { get; private set; }

        internal SocketConnectionListener(
            EndPoint endpoint,
            SocketTransportOptions options,
            ISocketsTrace trace)
        {
            EndPoint = endpoint;
            _trace = trace;
            _options = options;
            _memoryPool = _options.MemoryPoolFactory();
            var ioQueueCount = options.IOQueueCount;

            if (ioQueueCount > 0)
            {
                _numSchedulers = ioQueueCount;
                _schedulers = new IOQueue[_numSchedulers];

                for (var i = 0; i < _numSchedulers; i++)
                {
                    _schedulers[i] = new IOQueue();
                }
            }
            else
            {
                var directScheduler = new PipeScheduler[] { PipeScheduler.ThreadPool };
                _numSchedulers = directScheduler.Length;
                _schedulers = directScheduler;
            }
        }

        internal void Bind()
        {
            if (_listenSocket != null)
            {
                throw new InvalidOperationException("Transport is already bound.");
            }

            Socket listenSocket;

            switch (EndPoint)
            {
                //case FileHandleEndPoint fileHandle:
                //    _socketHandle = new SafeSocketHandle((IntPtr)fileHandle.FileHandle, ownsHandle: true);
                //    listenSocket = new Socket(_socketHandle);
                //    break;
                case UnixDomainSocketEndPoint unix:
                    listenSocket = new Socket(unix.AddressFamily, SocketType.Stream, ProtocolType.Unspecified);
                    BindSocket();
                    break;
                case IPEndPoint ip:
                    listenSocket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    // Kestrel expects IPv6Any to bind to both IPv6 and IPv4
                    if (ip.Address == IPAddress.IPv6Any)
                    {
                        listenSocket.DualMode = true;
                    }
                    BindSocket();
                    break;
                default:
                    listenSocket = new Socket(EndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                    BindSocket();
                    break;
            }

            void BindSocket()
            {
                try
                {
                    listenSocket.Bind(EndPoint);
                }
                catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse)
                {
                    throw new AddressInUseException(e.Message, e);
                }
            }

            EndPoint = listenSocket.LocalEndPoint;

            listenSocket.Listen(_options.Backlog);

            _listenSocket = listenSocket;
        }

        public async ValueTask<ConnectionContext> AcceptAsync(CancellationToken cancellationToken = default)
        {
            while (true)
            {
                try
                {
                    var acceptSocket = await _listenSocket.AcceptAsync();

                    // Only apply no delay to Tcp based endpoints
                    if (acceptSocket.LocalEndPoint is IPEndPoint)
                    {
                        acceptSocket.NoDelay = _options.NoDelay;
                    }

                    var connection = new SocketConnection(acceptSocket, _memoryPool, _schedulers[_schedulerIndex], _trace,
                        _options.MaxReadBufferSize, _options.MaxWriteBufferSize, _options.WaitForDataBeforeAllocatingBuffer,
                        _options.UnsafePreferInlineScheduling);

                    connection.Start();

                    _schedulerIndex = (_schedulerIndex + 1) % _numSchedulers;

                    return connection;
                }
                catch (ObjectDisposedException)
                {
                    // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done
                    return null;
                }
                catch (SocketException e) when (e.SocketErrorCode == SocketError.OperationAborted)
                {
                    // A call was made to UnbindAsync/DisposeAsync just return null which signals we're done
                    return null;
                }
                catch (SocketException)
                {
                    // The connection got reset while it was in the backlog, so we try again.
                    _trace.ConnectionReset(connectionId: "(null)");
                }
            }
        }

        public ValueTask UnbindAsync(CancellationToken cancellationToken = default)
        {
            _listenSocket?.Dispose();

            _socketHandle?.Dispose();
            return default;
        }

        public ValueTask DisposeAsync()
        {
            _listenSocket?.Dispose();

            _socketHandle?.Dispose();

            // Dispose the memory pool
            _memoryPool.Dispose();
            return default;
        }
    }
    /// <summary>
    /// Represents an application.
    /// </summary>
    /// <typeparam name="TContext">The context associated with the application.</typeparam>
    public interface IHttpApplication<TContext> where TContext : notnull
    {
        /// <summary>
        /// Create a TContext given a collection of HTTP features.
        /// </summary>
        /// <param name="contextFeatures">A collection of HTTP features to be used for creating the TContext.</param>
        /// <returns>The created TContext.</returns>
        TContext CreateContext(IFeatureCollection contextFeatures);

        /// <summary>
        /// Asynchronously processes an TContext.
        /// </summary>
        /// <param name="context">The TContext that the operation will process.</param>
        Task ProcessRequestAsync(TContext context);

        /// <summary>
        /// Dispose a given TContext.
        /// </summary>
        /// <param name="context">The TContext to be disposed.</param>
        /// <param name="exception">The Exception thrown when processing did not complete successfully, otherwise null.</param>
        void DisposeContext(TContext context, Exception exception);
    }

    /// <summary>
    /// 定义一个连接限制中间件 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    internal class ConnectionLimitMiddleware<T> where T : BaseConnectionContext
    {
        private readonly Func<T, Task> _next;
        private readonly ResourceCounter _concurrentConnectionCounter;
        private readonly IKestrelTrace _trace;

        public ConnectionLimitMiddleware(Func<T, Task> next, long connectionLimit, IKestrelTrace trace)
            : this(next, ResourceCounter.Quota(connectionLimit), trace)
        {
        }

        // For Testing
        internal ConnectionLimitMiddleware(Func<T, Task> next, ResourceCounter concurrentConnectionCounter, IKestrelTrace trace)
        {
            _next = next;
            _concurrentConnectionCounter = concurrentConnectionCounter;
            _trace = trace;
        }

        public async Task OnConnectionAsync(T connection)
        {
            if (!_concurrentConnectionCounter.TryLockOne())
            {
                KestrelEventSource.Log.ConnectionRejected(connection.ConnectionId);
                _trace.ConnectionRejected(connection.ConnectionId);
                await connection.DisposeAsync();
                return;
            }

            var releasor = new ConnectionReleasor(_concurrentConnectionCounter);

            try
            {
                connection.Features.Set<IDecrementConcurrentConnectionCountFeature>(releasor);
                await _next(connection);
            }
            finally
            {
                releasor.ReleaseConnection();
            }
        }

        private class ConnectionReleasor : IDecrementConcurrentConnectionCountFeature
        {
            private readonly ResourceCounter _concurrentConnectionCounter;
            private bool _connectionReleased;

            public ConnectionReleasor(ResourceCounter normalConnectionCounter)
            {
                _concurrentConnectionCounter = normalConnectionCounter;
            }

            public void ReleaseConnection()
            {
                if (!_connectionReleased)
                {
                    _connectionReleased = true;
                    _concurrentConnectionCounter.ReleaseOne();
                }
            }
        }
    }
    /// <summary>
    /// A connection feature allowing middleware to stop counting connections towards <see cref="KestrelServerLimits.MaxConcurrentConnections"/>.
    /// This is used by Kestrel internally to stop counting upgraded connections towards this limit.
    /// </summary>
    public interface IDecrementConcurrentConnectionCountFeature
    {
        /// <summary>
        /// Idempotent method to stop counting a connection towards <see cref="KestrelServerLimits.MaxConcurrentConnections"/>.
        /// </summary>
        void ReleaseConnection();
    }
    /// <summary>
    /// A function that can process a connection.
    /// </summary>
    /// <param name="connection">A <see cref="ConnectionContext" /> representing the connection.</param>
    /// <returns>A <see cref="Task"/> that represents the connection lifetime. When the task completes, the connection will be closed.</returns>
    public delegate Task ConnectionDelegate(ConnectionContext connection);

    public class KestrelConfigurationLoader
    {
        private bool _loaded = false;

        internal KestrelConfigurationLoader(
            KestrelServerOptions options,
            IConfiguration configuration,
            IHostEnvironment hostEnvironment,
            bool reloadOnChange,
            ILogger<KestrelServer> logger)
        {
            Options = options ?? throw new ArgumentNullException(nameof(options));
            Configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            HostEnvironment = hostEnvironment ?? throw new ArgumentNullException(nameof(hostEnvironment));
            Logger = logger ?? throw new ArgumentNullException(nameof(logger));
            //HttpsLogger = httpsLogger ?? throw new ArgumentNullException(nameof(logger));

            ReloadOnChange = reloadOnChange;

            ConfigurationReader = new ConfigurationReader(configuration);
            // CertificateConfigLoader = new CertificateConfigLoader(hostEnvironment, logger);
        }

        public KestrelServerOptions Options { get; }
        public IConfiguration Configuration { get; internal set; }

        /// <summary>
        /// If <see langword="true" />, Kestrel will dynamically update endpoint bindings when configuration changes.
        /// This will only reload endpoints defined in the "Endpoints" section of your Kestrel configuration. Endpoints defined in code will not be reloaded.
        /// </summary>
        internal bool ReloadOnChange { get; }

        private IHostEnvironment HostEnvironment { get; }
        private ILogger<KestrelServer> Logger { get; }
        //private ILogger<HttpsConnectionMiddleware> HttpsLogger { get; }

        private ConfigurationReader ConfigurationReader { get; set; }

        //private ICertificateConfigLoader CertificateConfigLoader { get; }

        //private IDictionary<string, Action<EndpointConfiguration>> EndpointConfigurations { get; }
        //    = new Dictionary<string, Action<EndpointConfiguration>>(0, StringComparer.OrdinalIgnoreCase);

        // Actions that will be delayed until Load so that they aren't applied if the configuration loader is replaced.
        private IList<Action> EndpointsToAdd { get; } = new List<Action>();

        private CertificateConfig DefaultCertificateConfig { get; set; }

        ///// <summary>
        ///// Specifies a configuration Action to run when an endpoint with the given name is loaded from configuration.
        ///// </summary>
        //public KestrelConfigurationLoader Endpoint(string name, Action<EndpointConfiguration> configureOptions)
        //{
        //    if (string.IsNullOrEmpty(name))
        //    {
        //        throw new ArgumentNullException(nameof(name));
        //    }

        //    EndpointConfigurations[name] = configureOptions ?? throw new ArgumentNullException(nameof(configureOptions));
        //    return this;
        //}

        /// <summary>
        /// Bind to given IP address and port.
        /// </summary>
        public KestrelConfigurationLoader Endpoint(IPAddress address, int port) => Endpoint(address, port, _ => { });

        /// <summary>
        /// Bind to given IP address and port.
        /// </summary>
        public KestrelConfigurationLoader Endpoint(IPAddress address, int port, Action<ListenOptions> configure)
        {
            if (address == null)
            {
                throw new ArgumentNullException(nameof(address));
            }

            return Endpoint(new IPEndPoint(address, port), configure);
        }

        /// <summary>
        /// Bind to given IP endpoint.
        /// </summary>
        public KestrelConfigurationLoader Endpoint(IPEndPoint endPoint) => Endpoint(endPoint, _ => { });

        /// <summary>
        /// Bind to given IP address and port.
        /// </summary>
        public KestrelConfigurationLoader Endpoint(IPEndPoint endPoint, Action<ListenOptions> configure)
        {
            if (endPoint == null)
            {
                throw new ArgumentNullException(nameof(endPoint));
            }
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            EndpointsToAdd.Add(() =>
            {
                Options.Listen(endPoint, configure);
            });

            return this;
        }

        /// <summary>
        /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported
        /// for this type of endpoint.
        /// </summary>
        public KestrelConfigurationLoader LocalhostEndpoint(int port) => LocalhostEndpoint(port, options => { });

        /// <summary>
        /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported
        /// for this type of endpoint.
        /// </summary>
        public KestrelConfigurationLoader LocalhostEndpoint(int port, Action<ListenOptions> configure)
        {
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            EndpointsToAdd.Add(() =>
            {
                Options.ListenLocalhost(port, configure);
            });

            return this;
        }

        /// <summary>
        /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported.
        /// </summary>
        public KestrelConfigurationLoader AnyIPEndpoint(int port) => AnyIPEndpoint(port, options => { });

        /// <summary>
        /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported.
        /// </summary>
        public KestrelConfigurationLoader AnyIPEndpoint(int port, Action<ListenOptions> configure)
        {
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            EndpointsToAdd.Add(() =>
            {
                Options.ListenAnyIP(port, configure);
            });

            return this;
        }

        /// <summary>
        /// Bind to given Unix domain socket path.
        /// </summary>
        public KestrelConfigurationLoader UnixSocketEndpoint(string socketPath) => UnixSocketEndpoint(socketPath, _ => { });

        /// <summary>
        /// Bind to given Unix domain socket path.
        /// </summary>
        public KestrelConfigurationLoader UnixSocketEndpoint(string socketPath, Action<ListenOptions> configure)
        {
            //if (socketPath == null)
            //{
            //    throw new ArgumentNullException(nameof(socketPath));
            //}
            //if (socketPath.Length == 0 || socketPath[0] != '/')
            //{
            //    throw new ArgumentException(CoreStrings.UnixSocketPathMustBeAbsolute, nameof(socketPath));
            //}
            //if (configure == null)
            //{
            //    throw new ArgumentNullException(nameof(configure));
            //}

            //EndpointsToAdd.Add(() =>
            //{
            //    Options.ListenUnixSocket(socketPath, configure);
            //});

            return this;
        }

        /// <summary>
        /// Open a socket file descriptor.
        /// </summary>
        public KestrelConfigurationLoader HandleEndpoint(ulong handle) => HandleEndpoint(handle, _ => { });

        /// <summary>
        /// Open a socket file descriptor.
        /// </summary>
        public KestrelConfigurationLoader HandleEndpoint(ulong handle, Action<ListenOptions> configure)
        {
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            //EndpointsToAdd.Add(() =>
            //{
            //    Options.ListenHandle(handle, configure);
            //});

            return this;
        }

        // Called from KestrelServerOptions.ApplyEndpointDefaults so it applies to even explicit Listen endpoints.
        // Does not require a call to Load.
        internal void ApplyEndpointDefaults(ListenOptions listenOptions)
        {
            var defaults = ConfigurationReader.EndpointDefaults;

            //if (defaults.Protocols.HasValue)
            //{
            //    listenOptions.Protocols = defaults.Protocols.Value;
            //}
        }

        //// Called from KestrelServerOptions.ApplyHttpsDefaults so it applies to even explicit Listen endpoints.
        //// Does not require a call to Load.
        //internal void ApplyHttpsDefaults(HttpsConnectionAdapterOptions httpsOptions)
        //{
        //    var defaults = ConfigurationReader.EndpointDefaults;

        //    if (defaults.SslProtocols.HasValue)
        //    {
        //        httpsOptions.SslProtocols = defaults.SslProtocols.Value;
        //    }

        //    if (defaults.ClientCertificateMode.HasValue)
        //    {
        //        httpsOptions.ClientCertificateMode = defaults.ClientCertificateMode.Value;
        //    }
        //}

        public void Load()
        {
            if (_loaded)
            {
                // The loader has already been run.
                return;
            }
            _loaded = true;

            Reload();

            foreach (var action in EndpointsToAdd)
            {
                action();
            }
        }

        // Adds endpoints from config to KestrelServerOptions.ConfigurationBackedListenOptions and configures some other options.
        // Any endpoints that were removed from the last time endpoints were loaded are returned.
        internal (List<ListenOptions>, List<ListenOptions>) Reload()
        {
            var endpointsToStop = Options.ConfigurationBackedListenOptions.ToList();
            var endpointsToStart = new List<ListenOptions>();

            Options.ConfigurationBackedListenOptions.Clear();
            DefaultCertificateConfig = null;

            ConfigurationReader = new ConfigurationReader(Configuration);

            LoadDefaultCert();

            foreach (var endpoint in ConfigurationReader.Endpoints)
            {
                //var listenOptions = AddressBinder.ParseAddress(endpoint.Url, out var https);

                //if (!https)
                //{
                //    ConfigurationReader.ThrowIfContainsHttpsOnlyConfiguration(endpoint);
                //}

                //Options.ApplyEndpointDefaults(listenOptions);

                //if (endpoint.Protocols.HasValue)
                //{
                //    listenOptions.Protocols = endpoint.Protocols.Value;
                //}
                //else
                //{
                //    // Ensure endpoint is reloaded if it used the default protocol and the protocol changed.
                //    // listenOptions.Protocols should already be set to this by ApplyEndpointDefaults.
                //    endpoint.Protocols = ConfigurationReader.EndpointDefaults.Protocols;
                //}

                //// Compare to UseHttps(httpsOptions => { })
                //var httpsOptions = new HttpsConnectionAdapterOptions();

                //if (https)
                //{
                //    // Defaults
                //    Options.ApplyHttpsDefaults(httpsOptions);

                //    if (endpoint.SslProtocols.HasValue)
                //    {
                //        httpsOptions.SslProtocols = endpoint.SslProtocols.Value;
                //    }
                //    else
                //    {
                //        // Ensure endpoint is reloaded if it used the default protocol and the SslProtocols changed.
                //        endpoint.SslProtocols = ConfigurationReader.EndpointDefaults.SslProtocols;
                //    }

                //    if (endpoint.ClientCertificateMode.HasValue)
                //    {
                //        httpsOptions.ClientCertificateMode = endpoint.ClientCertificateMode.Value;
                //    }
                //    else
                //    {
                //        // Ensure endpoint is reloaded if it used the default mode and the ClientCertificateMode changed.
                //        endpoint.ClientCertificateMode = ConfigurationReader.EndpointDefaults.ClientCertificateMode;
                //    }

                //    // A cert specified directly on the endpoint overrides any defaults.
                //    httpsOptions.ServerCertificate = CertificateConfigLoader.LoadCertificate(endpoint.Certificate, endpoint.Name)
                //        ?? httpsOptions.ServerCertificate;

                //    if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                //    {
                //        // Fallback
                //        Options.ApplyDefaultCert(httpsOptions);

                //        // Ensure endpoint is reloaded if it used the default certificate and the certificate changed.
                //        endpoint.Certificate = DefaultCertificateConfig;
                //    }
                //}

                //// Now that defaults have been loaded, we can compare to the currently bound endpoints to see if the config changed.
                //// There's no reason to rerun an EndpointConfigurations callback if nothing changed.
                //var matchingBoundEndpoints = endpointsToStop.Where(o => o.EndpointConfig == endpoint).ToList();

                //if (matchingBoundEndpoints.Count > 0)
                //{
                //    endpointsToStop.RemoveAll(o => o.EndpointConfig == endpoint);
                //    Options.ConfigurationBackedListenOptions.AddRange(matchingBoundEndpoints);
                //    continue;
                //}

                //if (EndpointConfigurations.TryGetValue(endpoint.Name, out var configureEndpoint))
                //{
                //    var endpointConfig = new EndpointConfiguration(https, listenOptions, httpsOptions, endpoint.ConfigSection);
                //    configureEndpoint(endpointConfig);
                //}

                //// EndpointDefaults or configureEndpoint may have added an https adapter.
                //if (https && !listenOptions.IsTls)
                //{
                //    if (endpoint.Sni.Count == 0)
                //    {
                //        if (httpsOptions.ServerCertificate == null && httpsOptions.ServerCertificateSelector == null)
                //        {
                //            throw new InvalidOperationException(CoreStrings.NoCertSpecifiedNoDevelopmentCertificateFound);
                //        }

                //        listenOptions.UseHttps(httpsOptions);
                //    }
                //    else
                //    {
                //        var sniOptionsSelector = new SniOptionsSelector(endpoint.Name, endpoint.Sni, CertificateConfigLoader, httpsOptions, listenOptions.Protocols, HttpsLogger);
                //        listenOptions.UseHttps(SniOptionsSelector.OptionsCallback, sniOptionsSelector, httpsOptions.HandshakeTimeout);
                //    }
                //}

                //listenOptions.EndpointConfig = endpoint;

                //endpointsToStart.Add(listenOptions);
                //Options.ConfigurationBackedListenOptions.Add(listenOptions);
            }

            return (endpointsToStop, endpointsToStart);
        }

        private void LoadDefaultCert()
        {
            //if (ConfigurationReader.Certificates.TryGetValue("Default", out var defaultCertConfig))
            //{
            //    var defaultCert = CertificateConfigLoader.LoadCertificate(defaultCertConfig, "Default");
            //    if (defaultCert != null)
            //    {
            //        DefaultCertificateConfig = defaultCertConfig;
            //        Options.DefaultCertificate = defaultCert;
            //    }
            //}
            //else
            //{
            //    var (certificate, certificateConfig) = FindDeveloperCertificateFile();
            //    if (certificate != null)
            //    {
            //        Logger.LocatedDevelopmentCertificate(certificate);
            //        DefaultCertificateConfig = certificateConfig;
            //        Options.DefaultCertificate = certificate;
            //    }
            //}
        }

        //private (X509Certificate2, CertificateConfig) FindDeveloperCertificateFile()
        //{
        //    string certificatePath = null;
        //    try
        //    {
        //        if (ConfigurationReader.Certificates.TryGetValue("Development", out var certificateConfig) &&
        //            certificateConfig.Path == null &&
        //            certificateConfig.Password != null &&
        //            TryGetCertificatePath(out certificatePath) &&
        //            File.Exists(certificatePath))
        //        {
        //            var certificate = new X509Certificate2(certificatePath, certificateConfig.Password);

        //            if (IsDevelopmentCertificate(certificate))
        //            {
        //                return (certificate, certificateConfig);
        //            }
        //        }
        //        else if (!string.IsNullOrEmpty(certificatePath))
        //        {
        //            Logger.FailedToLocateDevelopmentCertificateFile(certificatePath);
        //        }
        //    }
        //    catch (CryptographicException)
        //    {
        //        Logger.FailedToLoadDevelopmentCertificate(certificatePath);
        //    }

        //    return (null, null);
        //}

        //private static bool IsDevelopmentCertificate(X509Certificate2 certificate)
        //{
        //    if (!string.Equals(certificate.Subject, "CN=localhost", StringComparison.Ordinal))
        //    {
        //        return false;
        //    }

        //    foreach (var ext in certificate.Extensions)
        //    {
        //        if (string.Equals(ext.Oid.Value, CertificateManager.AspNetHttpsOid, StringComparison.Ordinal))
        //        {
        //            return true;
        //        }
        //    }

        //    return false;
        //}

        //private bool TryGetCertificatePath(out string path)
        //{
        //    // This will go away when we implement
        //    // https://github.com/aspnet/Hosting/issues/1294
        //    var appData = Environment.GetEnvironmentVariable("APPDATA");
        //    var home = Environment.GetEnvironmentVariable("HOME");
        //    var basePath = appData != null ? Path.Combine(appData, "ASP.NET", "https") : null;
        //    basePath = basePath ?? (home != null ? Path.Combine(home, ".aspnet", "https") : null);
        //    path = basePath != null ? Path.Combine(basePath, $"{HostEnvironment.ApplicationName}.pfx") : null;
        //    return path != null;
        //}
    }

    /// <summary>
    /// Provides programmatic configuration of Kestrel-specific features.
    /// </summary>
    public class KestrelServerOptions
    {
        // internal to fast-path header decoding when RequestHeaderEncodingSelector is unchanged.
        internal static readonly Func<string, Encoding> DefaultRequestHeaderEncodingSelector = _ => null;

        private Func<string, Encoding> _requestHeaderEncodingSelector = DefaultRequestHeaderEncodingSelector;

        // The following two lists configure the endpoints that Kestrel should listen to. If both lists are empty, the "urls" config setting (e.g. UseUrls) is used.
        internal List<ListenOptions> CodeBackedListenOptions { get; } = new List<ListenOptions>();
        internal List<ListenOptions> ConfigurationBackedListenOptions { get; } = new List<ListenOptions>();
        internal IEnumerable<ListenOptions> ListenOptions => CodeBackedListenOptions.Concat(ConfigurationBackedListenOptions);

        // For testing and debugging.
        internal List<ListenOptions> OptionsInUse { get; } = new List<ListenOptions>();

        /// <summary>
        /// Gets or sets whether the <c>Server</c> header should be included in each response.
        /// </summary>
        /// <remarks>
        /// Defaults to true.
        /// </remarks>
        public bool AddServerHeader { get; set; } = true;

        /// <summary>
        /// Gets or sets a value that controls whether dynamic compression of response headers is allowed.
        /// For more information about the security considerations of HPack dynamic header compression, visit
        /// https://tools.ietf.org/html/rfc7541#section-7.
        /// </summary>
        /// <remarks>
        /// Defaults to true.
        /// </remarks>
        public bool AllowResponseHeaderCompression { get; set; } = true;

        /// <summary>
        /// Gets or sets a value that controls whether synchronous IO is allowed for the <see cref="HttpContext.Request"/> and <see cref="HttpContext.Response"/>
        /// </summary>
        /// <remarks>
        /// Defaults to false.
        /// </remarks>
        public bool AllowSynchronousIO { get; set; } = false;

        /// <summary>
        /// Gets or sets a value that controls whether the string values materialized
        /// will be reused across requests; if they match, or if the strings will always be reallocated.
        /// </summary>
        /// <remarks>
        /// Defaults to false.
        /// </remarks>
        public bool DisableStringReuse { get; set; } = false;

        /// <summary>
        /// Controls whether to return the AltSvcHeader from on an HTTP/2 or lower response for HTTP/3
        /// </summary>
        /// <remarks>
        /// Defaults to false.
        /// </remarks>
        public bool EnableAltSvc { get; set; } = false;

        /// <summary>
        /// Gets or sets a callback that returns the <see cref="Encoding"/> to decode the value for the specified request header name,
        /// or <see langword="null"/> to use the default <see cref="UTF8Encoding"/>.
        /// </summary>
        public Func<string, Encoding> RequestHeaderEncodingSelector
        {
            get => _requestHeaderEncodingSelector;
            set => _requestHeaderEncodingSelector = value ?? throw new ArgumentNullException(nameof(value));
        }

        /// <summary>
        /// Enables the Listen options callback to resolve and use services registered by the application during startup.
        /// Typically initialized by UseKestrel()"/>.
        /// </summary>
        public IServiceProvider ApplicationServices { get; set; }

        /// <summary>
        /// Provides access to request limit options.
        /// </summary>
        public KestrelServerLimits Limits { get; } = new KestrelServerLimits();

        /// <summary>
        /// Provides a configuration source where endpoints will be loaded from on server start.
        /// The default is <see langword="null"/>.
        /// </summary>
        public KestrelConfigurationLoader ConfigurationLoader { get; set; }

        /// <summary>
        /// A default configuration action for all endpoints. Use for Listen, configuration, the default url, and URLs.
        /// </summary>
        private Action<ListenOptions> EndpointDefaults { get; set; } = _ => { };

        ///// <summary>
        ///// A default configuration action for all https endpoints.
        ///// </summary>
        //private Action<HttpsConnectionAdapterOptions> HttpsDefaults { get; set; } = _ => { };

        ///// <summary>
        ///// The default server certificate for https endpoints. This is applied lazily after HttpsDefaults and user options.
        ///// </summary>
        //internal X509Certificate2 DefaultCertificate { get; set; }

        /// <summary>
        /// Has the default dev certificate load been attempted?
        /// </summary>
        internal bool IsDevCertLoaded { get; set; }

        /// <summary>
        /// Specifies a configuration Action to run for each newly created endpoint. Calling this again will replace
        /// the prior action.
        /// </summary>
        public void ConfigureEndpointDefaults(Action<ListenOptions> configureOptions)
        {
            EndpointDefaults = configureOptions ?? throw new ArgumentNullException(nameof(configureOptions));
        }

        internal void ApplyEndpointDefaults(ListenOptions listenOptions)
        {
            listenOptions.KestrelServerOptions = this;
            ConfigurationLoader?.ApplyEndpointDefaults(listenOptions);
            EndpointDefaults(listenOptions);
        }

        ///// <summary>
        ///// Specifies a configuration Action to run for each newly created https endpoint. Calling this again will replace
        ///// the prior action.
        ///// </summary>
        //public void ConfigureHttpsDefaults(Action<HttpsConnectionAdapterOptions> configureOptions)
        //{
        //    HttpsDefaults = configureOptions ?? throw new ArgumentNullException(nameof(configureOptions));
        //}

        //internal void ApplyHttpsDefaults(HttpsConnectionAdapterOptions httpsOptions)
        //{
        //    ConfigurationLoader?.ApplyHttpsDefaults(httpsOptions);
        //    HttpsDefaults(httpsOptions);
        //}

        //internal void ApplyDefaultCert(HttpsConnectionAdapterOptions httpsOptions)
        //{
        //    if (httpsOptions.ServerCertificate != null || httpsOptions.ServerCertificateSelector != null)
        //    {
        //        return;
        //    }

        //    EnsureDefaultCert();

        //    httpsOptions.ServerCertificate = DefaultCertificate;
        //}

        private void EnsureDefaultCert()
        {
            //if (DefaultCertificate == null && !IsDevCertLoaded)
            //{
            //    IsDevCertLoaded = true; // Only try once
            //    var logger = ApplicationServices!.GetRequiredService<ILogger<KestrelServer>>();
            //    try
            //    {
            //        DefaultCertificate = CertificateManager.Instance.ListCertificates(StoreName.My, StoreLocation.CurrentUser, isValid: true)
            //            .FirstOrDefault();

            //        if (DefaultCertificate != null)
            //        {
            //            var status = CertificateManager.Instance.CheckCertificateState(DefaultCertificate, interactive: false);
            //            if (!status.Result)
            //            {
            //                // Display a warning indicating to the user that a prompt might appear and provide instructions on what to do in that
            //                // case. The underlying implementation of this check is specific to Mac OS and is handled within CheckCertificateState.
            //                // Kestrel must NEVER cause a UI prompt on a production system. We only attempt this here because Mac OS is not supported
            //                // in production.
            //                logger.DeveloperCertificateFirstRun(status.Message);

            //                // Now that we've displayed a warning in the logs so that the user gets a notification that a prompt might appear, try
            //                // and access the certificate key, which might trigger a prompt.
            //                status = CertificateManager.Instance.CheckCertificateState(DefaultCertificate, interactive: true);
            //                if (!status.Result)
            //                {
            //                    logger.BadDeveloperCertificateState();
            //                }
            //            }

            //            logger.LocatedDevelopmentCertificate(DefaultCertificate);
            //        }
            //        else
            //        {
            //            logger.UnableToLocateDevelopmentCertificate();
            //        }
            //    }
            //    catch
            //    {
            //        logger.UnableToLocateDevelopmentCertificate();
            //    }
            //}
        }

        /// <summary>
        /// Creates a configuration loader for setting up Kestrel.
        /// </summary>
        /// <returns>A <see cref="KestrelConfigurationLoader"/> for configuring endpoints.</returns>
        public KestrelConfigurationLoader Configure() => Configure(new ConfigurationBuilder().Build());

        /// <summary>
        /// Creates a configuration loader for setting up Kestrel that takes an <see cref="IConfiguration"/> as input.
        /// This configuration must be scoped to the configuration section for Kestrel.
        /// Call <see cref="Configure(IConfiguration, bool)"/> to enable dynamic endpoint binding updates.
        /// </summary>
        /// <param name="config">The configuration section for Kestrel.</param>
        /// <returns>A <see cref="KestrelConfigurationLoader"/> for further endpoint configuration.</returns>
        public KestrelConfigurationLoader Configure(IConfiguration config) => Configure(config, reloadOnChange: false);

        /// <summary>
        /// Creates a configuration loader for setting up Kestrel that takes an <see cref="IConfiguration"/> as input.
        /// This configuration must be scoped to the configuration section for Kestrel.
        /// </summary>
        /// <param name="config">The configuration section for Kestrel.</param>
        /// <param name="reloadOnChange">
        /// If <see langword="true"/>, Kestrel will dynamically update endpoint bindings when configuration changes.
        /// This will only reload endpoints defined in the "Endpoints" section of your <paramref name="config"/>. Endpoints defined in code will not be reloaded.
        /// </param>
        /// <returns>A <see cref="KestrelConfigurationLoader"/> for further endpoint configuration.</returns>
        public KestrelConfigurationLoader Configure(IConfiguration config, bool reloadOnChange)
        {
            if (ApplicationServices is null)
            {
                throw new InvalidOperationException($"{nameof(ApplicationServices)} must not be null. This is normally set automatically via {nameof(IConfigureOptions<KestrelServerOptions>)}.");
            }

            var hostEnvironment = ApplicationServices.GetRequiredService<IHostEnvironment>();
            var logger = ApplicationServices.GetRequiredService<ILogger<KestrelServer>>();
            //var httpsLogger = ApplicationServices.GetRequiredService<ILogger<HttpsConnectionMiddleware>>();

            var loader = new KestrelConfigurationLoader(this, config, hostEnvironment, reloadOnChange, logger);
            ConfigurationLoader = loader;
            return loader;
        }

        /// <summary>
        /// Bind to given IP address and port.
        /// </summary>
        public void Listen(IPAddress address, int port)
        {
            Listen(address, port, _ => { });
        }

        /// <summary>
        /// Bind to given IP address and port.
        /// The callback configures endpoint-specific settings.
        /// </summary>
        public void Listen(IPAddress address, int port, Action<ListenOptions> configure)
        {
            if (address == null)
            {
                throw new ArgumentNullException(nameof(address));
            }

            Listen(new IPEndPoint(address, port), configure);
        }

        /// <summary>
        /// Bind to the given IP endpoint.
        /// </summary>
        public void Listen(IPEndPoint endPoint)
        {
            Listen((EndPoint)endPoint);
        }

        /// <summary>
        /// Bind to the given endpoint.
        /// </summary>
        /// <param name="endPoint"></param>
        public void Listen(EndPoint endPoint)
        {
            Listen(endPoint, _ => { });
        }

        /// <summary>
        /// Bind to given IP address and port.
        /// The callback configures endpoint-specific settings.
        /// </summary>
        public void Listen(IPEndPoint endPoint, Action<ListenOptions> configure)
        {
            Listen((EndPoint)endPoint, configure);
        }

        /// <summary>
        /// Bind to the given endpoint.
        /// The callback configures endpoint-specific settings.
        /// </summary>
        public void Listen(EndPoint endPoint, Action<ListenOptions> configure)
        {
            if (endPoint == null)
            {
                throw new ArgumentNullException(nameof(endPoint));
            }
            if (configure == null)
            {
                throw new ArgumentNullException(nameof(configure));
            }

            var listenOptions = new ListenOptions(endPoint);
            ApplyEndpointDefaults(listenOptions);
            configure(listenOptions);
            CodeBackedListenOptions.Add(listenOptions);
        }

        /// <summary>
        /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported
        /// for this type of endpoint.
        /// </summary>
        public void ListenLocalhost(int port) => ListenLocalhost(port, options => { });

        /// <summary>
        /// Listens on ::1 and 127.0.0.1 with the given port. Requesting a dynamic port by specifying 0 is not supported
        /// for this type of endpoint.
        /// </summary>
        public void ListenLocalhost(int port, Action<ListenOptions> configure)
        {
            //if (configure == null)
            //{
            //    throw new ArgumentNullException(nameof(configure));
            //}

            //var listenOptions = new LocalhostListenOptions(port);
            //ApplyEndpointDefaults(listenOptions);
            //configure(listenOptions);
            //CodeBackedListenOptions.Add(listenOptions);
        }

        /// <summary>
        /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported.
        /// </summary>
        public void ListenAnyIP(int port) => ListenAnyIP(port, options => { });

        /// <summary>
        /// Listens on all IPs using IPv6 [::], or IPv4 0.0.0.0 if IPv6 is not supported.
        /// </summary>
        public void ListenAnyIP(int port, Action<ListenOptions> configure)
        {
            //if (configure == null)
            //{
            //    throw new ArgumentNullException(nameof(configure));
            //}

            //var listenOptions = new AnyIPListenOptions(port);
            //ApplyEndpointDefaults(listenOptions);
            //configure(listenOptions);
            //CodeBackedListenOptions.Add(listenOptions);
        }

        ///// <summary>
        ///// Bind to given Unix domain socket path.
        ///// </summary>
        //public void ListenUnixSocket(string socketPath)
        //{
        //    ListenUnixSocket(socketPath, _ => { });
        //}

        ///// <summary>
        ///// Bind to given Unix domain socket path.
        ///// Specify callback to configure endpoint-specific settings.
        ///// </summary>
        //public void ListenUnixSocket(string socketPath, Action<ListenOptions> configure)
        //{
        //    if (socketPath == null)
        //    {
        //        throw new ArgumentNullException(nameof(socketPath));
        //    }

        //    if (!Path.IsPathRooted(socketPath))
        //    {
        //        throw new ArgumentException(CoreStrings.UnixSocketPathMustBeAbsolute, nameof(socketPath));
        //    }
        //    if (configure == null)
        //    {
        //        throw new ArgumentNullException(nameof(configure));
        //    }

        //    var listenOptions = new ListenOptions(socketPath);
        //    ApplyEndpointDefaults(listenOptions);
        //    configure(listenOptions);
        //    CodeBackedListenOptions.Add(listenOptions);
        //}

        ///// <summary>
        ///// Open a socket file descriptor.
        ///// </summary>
        //public void ListenHandle(ulong handle)
        //{
        //    ListenHandle(handle, _ => { });
        //}

        ///// <summary>
        ///// Open a socket file descriptor.
        ///// The callback configures endpoint-specific settings.
        ///// </summary>
        //public void ListenHandle(ulong handle, Action<ListenOptions> configure)
        //{
        //    if (configure == null)
        //    {
        //        throw new ArgumentNullException(nameof(configure));
        //    }

        //    var listenOptions = new ListenOptions(handle);
        //    ApplyEndpointDefaults(listenOptions);
        //    configure(listenOptions);
        //    CodeBackedListenOptions.Add(listenOptions);
        //}
    }

    //待清理
    internal sealed class AnyIPListenOptions : ListenOptions
    {
        internal AnyIPListenOptions(int port)
            : base(new IPEndPoint(IPAddress.IPv6Any, port))
        {
        }

        internal override async Task BindAsync(AddressBindContext context)
        {
            await Task.CompletedTask;
            // when address is 'http://hostname:port', 'http://*:port', or 'http://+:port'
            //try
            //{
            //    await base.BindAsync(context).ConfigureAwait(false);
            //}
            //catch (Exception ex) when (!(ex is IOException))
            //{
            //    context.Logger.LogDebug(CoreStrings.FormatFallbackToIPv4Any(IPEndPoint.Port));

            //    // for machines that do not support IPv6
            //    EndPoint = new IPEndPoint(IPAddress.Any, IPEndPoint.Port);
            //    await base.BindAsync(context).ConfigureAwait(false);
            //}
        }
    }

    /// <summary>
    /// Defines an interface that provides the mechanisms to configure a connection pipeline.
    /// </summary>
    public interface IConnectionBuilder
    {
        /// <summary>
        /// Gets the <see cref="IServiceProvider"/> that provides access to the application's service container.
        /// </summary>
        IServiceProvider ApplicationServices { get; }

        /// <summary>
        /// Adds a middleware delegate to the application's connection pipeline.
        /// </summary>
        /// <param name="middleware">The middleware delegate.</param>
        /// <returns>The <see cref="IConnectionBuilder"/>.</returns>
        IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware);

        /// <summary>
        /// Builds the delegate used by this application to process connections.
        /// </summary>
        /// <returns>The connection handling delegate.</returns>
        ConnectionDelegate Build();
    }

    /// <summary>
    /// Describes either an <see cref="IPEndPoint"/>, Unix domain socket path, or a file descriptor for an already open
    /// socket that Kestrel should bind to or open.
    /// </summary>
    public class ListenOptions : IConnectionBuilder 
    {
        internal static readonly TerminalProtocols DefaultHttpProtocols = TerminalProtocols.tcp;

        internal readonly List<Func<ConnectionDelegate, ConnectionDelegate>> _middleware = new List<Func<ConnectionDelegate, ConnectionDelegate>>();
        //internal readonly List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>> _multiplexedMiddleware = new List<Func<MultiplexedConnectionDelegate, MultiplexedConnectionDelegate>>();

        internal ListenOptions(EndPoint endPoint)
        {
            EndPoint = endPoint;
        }
        public TerminalProtocols Protocols { get; set; } = DefaultHttpProtocols;
        //internal ListenOptions(string socketPath)
        //{
        //    EndPoint = new UnixDomainSocketEndPoint(socketPath);
        //}

        //internal ListenOptions(ulong fileHandle)
        //    : this(fileHandle, FileHandleType.Auto)
        //{
        //}

        //internal ListenOptions(ulong fileHandle, FileHandleType handleType)
        //{
        //    EndPoint = new FileHandleEndPoint(fileHandle, handleType);
        //}

        public EndPoint EndPoint { get; internal set; }

        // For comparing bound endpoints to changed config during endpoint config reload.
        internal EndpointConfig EndpointConfig { get; set; }

        // IPEndPoint is mutable so port 0 can be updated to the bound port.
        /// <summary>
        /// The <see cref="IPEndPoint"/> to bind to.
        /// Only set if the <see cref="ListenOptions"/> <see cref="Type"/> is <see cref="IPEndPoint"/>.
        /// </summary>
        public IPEndPoint IPEndPoint => EndPoint as IPEndPoint;

 
        /// <summary>
        /// Enables connection middleware to resolve and use services registered by the application during startup.
        /// Only set if accessed from the callback of a <see cref="KestrelServerOptions"/> Listen* method.
        /// </summary>
        public KestrelServerOptions KestrelServerOptions { get; internal set; }
 
        public IServiceProvider ApplicationServices => KestrelServerOptions?.ApplicationServices;


        /// <summary>
        /// Adds a middleware delegate to the connection pipeline.
        /// Configured by the <c>UseHttps()</c> and <see cref="Hosting.ListenOptionsConnectionLoggingExtensions.UseConnectionLogging(ListenOptions)"/>
        /// extension methods.
        /// </summary>
        /// <param name="middleware">The middleware delegate.</param>
        /// <returns>The <see cref="IConnectionBuilder"/>.</returns>
        public IConnectionBuilder Use(Func<ConnectionDelegate, ConnectionDelegate> middleware)
        {
            _middleware.Add(middleware);
            return this;
        }

        public ConnectionDelegate Build()
        {
            ConnectionDelegate app = context =>
            {
                return Task.CompletedTask;
            };

            for (int i = _middleware.Count - 1; i >= 0; i--)
            {
                var component = _middleware[i];
                app = component(app);
            }

            return app;
        }


        internal virtual async Task BindAsync(AddressBindContext context)
        {
            await Task.CompletedTask;
            //await AddressBinder.BindEndpointAsync(this, context).ConfigureAwait(false);
            //context.Addresses.Add(GetDisplayName());
        }
    }

    /// <summary>
    /// Specifies the address used by the server.
    /// </summary>
    public interface IServerAddressesFeature
    {
        /// <summary>
        /// An <see cref="ICollection{T}" /> of addresses used by the server.
        /// </summary>
        ICollection<string> Addresses { get; }

        /// <summary>
        /// <see langword="true" /> to prefer URLs configured by the host rather than the server.
        /// </summary>
        bool PreferHostingUrls { get; set; }
    }
    internal class ServerAddressesFeature : IServerAddressesFeature
    {
        public ServerAddressesCollection InternalCollection { get; } = new ServerAddressesCollection();

        ICollection<string> IServerAddressesFeature.Addresses => InternalCollection.PublicCollection;
        public bool PreferHostingUrls { get; set; }
    }
    internal class AddressBindContext
    {
        public ServerAddressesFeature ServerAddressesFeature { get; set; }
        public ICollection<string> Addresses => ServerAddressesFeature.InternalCollection;

        public KestrelServerOptions ServerOptions { get; set; }
        public ILogger Logger { get; set; }

        public Func<ListenOptions, Task> CreateBinding { get; set; }
    }
    internal class ServerAddressesCollection : ICollection<string>
    {
        private readonly List<string> _addresses = new List<string>();
        private readonly PublicServerAddressesCollection _publicCollection;

        public ServerAddressesCollection()
        {
            _publicCollection = new PublicServerAddressesCollection(this);
        }

        public ICollection<string> PublicCollection => _publicCollection;

        public bool IsReadOnly => false;

        public int Count
        {
            get
            {
                lock (_addresses)
                {
                    return _addresses.Count;
                }
            }
        }

        public void PreventPublicMutation()
        {
            lock (_addresses)
            {
                _publicCollection.IsReadOnly = true;
            }
        }

        public void Add(string item)
        {
            lock (_addresses)
            {
                _addresses.Add(item);
            }
        }

        public bool Remove(string item)
        {
            lock (_addresses)
            {
                return _addresses.Remove(item);
            }
        }

        public void Clear()
        {
            lock (_addresses)
            {
                _addresses.Clear();
            }
        }

        public bool Contains(string item)
        {
            lock (_addresses)
            {
                return _addresses.Contains(item);
            }
        }

        public void CopyTo(string[] array, int arrayIndex)
        {
            lock (_addresses)
            {
                _addresses.CopyTo(array, arrayIndex);
            }
        }

        public IEnumerator<string> GetEnumerator()
        {
            lock (_addresses)
            {
                // Copy inside the lock.
                return new List<string>(_addresses).GetEnumerator();
            }
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        private class PublicServerAddressesCollection : ICollection<string>
        {
            private readonly ServerAddressesCollection _addressesCollection;
            private readonly object _addressesLock;

            public PublicServerAddressesCollection(ServerAddressesCollection addresses)
            {
                _addressesCollection = addresses;
                _addressesLock = addresses._addresses;
            }

            public bool IsReadOnly { get; set; }

            public int Count => _addressesCollection.Count;

            public void Add(string item)
            {
                lock (_addressesLock)
                {
                    ThrowIfReadonly();
                    _addressesCollection.Add(item);
                }
            }

            public bool Remove(string item)
            {
                lock (_addressesLock)
                {
                    ThrowIfReadonly();
                    return _addressesCollection.Remove(item);
                }
            }

            public void Clear()
            {
                lock (_addressesLock)
                {
                    ThrowIfReadonly();
                    _addressesCollection.Clear();
                }
            }

            public bool Contains(string item)
            {
                return _addressesCollection.Contains(item);
            }

            public void CopyTo(string[] array, int arrayIndex)
            {
                _addressesCollection.CopyTo(array, arrayIndex);
            }

            public IEnumerator<string> GetEnumerator()
            {
                return _addressesCollection.GetEnumerator();
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                return _addressesCollection.GetEnumerator();
            }

            [StackTraceHidden]
            private void ThrowIfReadonly()
            {
                if (IsReadOnly)
                {
                    throw new InvalidOperationException($"{nameof(IServerAddressesFeature)}.{nameof(IServerAddressesFeature.Addresses)} cannot be modified after the server has started.");
                }
            }
        }
    }
    /// <summary>
    /// Attribute to add to non-returning throw only methods, 
    /// to restore the stack trace back to what it would be if the throw was in-place
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct, Inherited = false)]
    internal sealed class StackTraceHiddenAttribute : Attribute
    {
        // https://github.com/dotnet/coreclr/blob/eb54e48b13fdfb7233b7bcd32b93792ba3e89f0c/src/mscorlib/shared/System/Diagnostics/StackTraceHiddenAttribute.cs
        public StackTraceHiddenAttribute() { }
    }

    public class KestrelServerLimits
    {
        // Matches the non-configurable default response buffer size for Kestrel in 1.0.0
        private long? _maxResponseBufferSize = 64 * 1024;

        // Matches the default client_max_body_size in nginx.
        // Also large enough that most requests should be under the limit.
        private long? _maxRequestBufferSize = 1024 * 1024;

        // Matches the default large_client_header_buffers in nginx.
        private int _maxRequestLineSize = 8 * 1024;

        // Matches the default large_client_header_buffers in nginx.
        private int _maxRequestHeadersTotalSize = 32 * 1024;

        // Matches the default maxAllowedContentLength in IIS (~28.6 MB)
        // https://www.iis.net/configreference/system.webserver/security/requestfiltering/requestlimits#005
        private long? _maxRequestBodySize = 30000000;

        // Matches the default LimitRequestFields in Apache httpd.
        private int _maxRequestHeaderCount = 100;

        // Matches the default http.sys connectionTimeout.
        private TimeSpan _keepAliveTimeout = TimeSpan.FromMinutes(2);

        private TimeSpan _requestHeadersTimeout = TimeSpan.FromSeconds(30);

        // Unlimited connections are allowed by default.
        private long? _maxConcurrentConnections = null;
        private long? _maxConcurrentUpgradedConnections = null;

        /// <summary>
        /// Gets or sets the maximum size of the response buffer before write
        /// calls begin to block or return tasks that don't complete until the
        /// buffer size drops below the configured limit.
        /// Defaults to 65,536 bytes (64 KB).
        /// </summary>
        /// <remarks>
        /// When set to null, the size of the response buffer is unlimited.
        /// When set to zero, all write calls will block or return tasks that
        /// don't complete until the entire response buffer is flushed.
        /// </remarks>
        public long? MaxResponseBufferSize
        {
            get => _maxResponseBufferSize;
            set
            {
                if (value.HasValue && value.Value < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "NonNegativeNumberOrNullRequired");
                }
                _maxResponseBufferSize = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum size of the request buffer.
        /// Defaults to 1,048,576 bytes (1 MB).
        /// </summary>
        /// <remarks>
        /// When set to null, the size of the request buffer is unlimited.
        /// </remarks>
        public long? MaxRequestBufferSize
        {
            get => _maxRequestBufferSize;
            set
            {
                if (value.HasValue && value.Value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveNumberOrNullRequired");
                }
                _maxRequestBufferSize = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum allowed size for the HTTP request line.
        /// Defaults to 8,192 bytes (8 KB).
        /// </summary>
        /// <remarks>
        /// For HTTP/2 this measures the total size of the required pseudo headers
        /// :method, :scheme, :authority, and :path.
        /// </remarks>
        public int MaxRequestLineSize
        {
            get => _maxRequestLineSize;
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveNumberRequired");
                }
                _maxRequestLineSize = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum allowed size for the HTTP request headers.
        /// Defaults to 32,768 bytes (32 KB).
        /// </summary>
        /// <remarks>
        /// </remarks>
        public int MaxRequestHeadersTotalSize
        {
            get => _maxRequestHeadersTotalSize;
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveNumberRequired");
                }
                _maxRequestHeadersTotalSize = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum allowed number of headers per HTTP request.
        /// Defaults to 100.
        /// </summary>
        /// <remarks>
        /// </remarks>
        public int MaxRequestHeaderCount
        {
            get => _maxRequestHeaderCount;
            set
            {
                if (value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveNumberRequired");
                }
                _maxRequestHeaderCount = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum allowed size of any request body in bytes.
        /// When set to null, the maximum request body size is unlimited.
        /// This limit has no effect on upgraded connections which are always unlimited.
        /// This can be overridden per-request via <see cref="IHttpMaxRequestBodySizeFeature"/>.
        /// Defaults to 30,000,000 bytes, which is approximately 28.6MB.
        /// </summary>
        /// <remarks>
        /// </remarks>
        public long? MaxRequestBodySize
        {
            get => _maxRequestBodySize;
            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "NonNegativeNumberOrNullRequired");
                }
                _maxRequestBodySize = value;
            }
        }

        /// <summary>
        /// Gets or sets the keep-alive timeout.
        /// Defaults to 2 minutes.
        /// </summary>
        /// <remarks>
        /// </remarks>
        public TimeSpan KeepAliveTimeout
        {
            get => _keepAliveTimeout;
            set
            {
                if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveTimeSpanRequired");
                }
                _keepAliveTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue;
            }
        }

        /// <summary>
        /// Gets or sets the maximum amount of time the server will spend receiving request headers.
        /// Defaults to 30 seconds.
        /// </summary>
        /// <remarks>
        /// </remarks>
        public TimeSpan RequestHeadersTimeout
        {
            get => _requestHeadersTimeout;
            set
            {
                if (value <= TimeSpan.Zero && value != Timeout.InfiniteTimeSpan)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveTimeSpanRequired");
                }
                _requestHeadersTimeout = value != Timeout.InfiniteTimeSpan ? value : TimeSpan.MaxValue;
            }
        }

        /// <summary>
        /// Gets or sets the maximum number of open connections. When set to null, the number of connections is unlimited.
        /// <para>
        /// Defaults to null.
        /// </para>
        /// </summary>
        /// <remarks>
        /// <para>
        /// When a connection is upgraded to another protocol, such as WebSockets, its connection is counted against the
        /// <see cref="MaxConcurrentUpgradedConnections" /> limit instead of <see cref="MaxConcurrentConnections" />.
        /// </para>
        /// </remarks>
        public long? MaxConcurrentConnections
        {
            get => _maxConcurrentConnections;
            set
            {
                if (value.HasValue && value <= 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "PositiveNumberOrNullRequired");
                }
                _maxConcurrentConnections = value;
            }
        }

        /// <summary>
        /// Gets or sets the maximum number of open, upgraded connections. When set to null, the number of upgraded connections is unlimited.
        /// An upgraded connection is one that has been switched from HTTP to another protocol, such as WebSockets.
        /// <para>
        /// Defaults to null.
        /// </para>
        /// </summary>
        /// <remarks>
        /// <para>
        /// When a connection is upgraded to another protocol, such as WebSockets, its connection is counted against the
        /// <see cref="MaxConcurrentUpgradedConnections" /> limit instead of <see cref="MaxConcurrentConnections" />.
        /// </para>
        /// </remarks>
        public long? MaxConcurrentUpgradedConnections
        {
            get => _maxConcurrentUpgradedConnections;
            set
            {
                if (value.HasValue && value < 0)
                {
                    throw new ArgumentOutOfRangeException(nameof(value), "NonNegativeNumberOrNullRequired");
                }
                _maxConcurrentUpgradedConnections = value;
            }
        }

        ///// <summary>
        ///// Limits only applicable to HTTP/2 connections.
        ///// </summary>
        //public Http2Limits Http2 { get; } = new Http2Limits();

        ///// <summary>
        ///// Limits only applicable to HTTP/3 connections.
        ///// </summary>
        //public Http3Limits Http3 { get; } = new Http3Limits();

        /// <summary>
        /// Gets or sets the request body minimum data rate in bytes/second.
        /// Setting this property to null indicates no minimum data rate should be enforced.
        /// This limit has no effect on upgraded connections which are always unlimited.
        /// This can be overridden per-request via <see cref="IHttpMinRequestBodyDataRateFeature"/>.
        /// Defaults to 240 bytes/second with a 5 second grace period.
        /// </summary>
        /// <remarks>
        /// </remarks>
        public MinDataRate MinRequestBodyDataRate { get; set; } =
            // Matches the default IIS minBytesPerSecond
            new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5));

        /// <summary>
        /// Gets or sets the response minimum data rate in bytes/second.
        /// Setting this property to null indicates no minimum data rate should be enforced.
        /// This limit has no effect on upgraded connections which are always unlimited.
        /// This can be overridden per-request via <see cref="IHttpMinResponseDataRateFeature"/>.
        /// <para>
        /// Defaults to 240 bytes/second with a 5 second grace period.
        /// </para>
        /// </summary>
        /// <remarks>
        /// <para>
        /// Contrary to the request body minimum data rate, this rate applies to the response status line and headers as well.
        /// </para>
        /// <para>
        /// This rate is enforced per write operation instead of being averaged over the life of the response. Whenever the server
        /// writes a chunk of data, a timer is set to the maximum of the grace period set in this property or the length of the write in
        /// bytes divided by the data rate (i.e. the maximum amount of time that write should take to complete with the specified data rate).
        /// The connection is aborted if the write has not completed by the time that timer expires.
        /// </para>
        /// </remarks>
        public MinDataRate MinResponseDataRate { get; set; } =
            // Matches the default IIS minBytesPerSecond
            new MinDataRate(bytesPerSecond: 240, gracePeriod: TimeSpan.FromSeconds(5));
    }


    /// <summary>
    /// 处理数据的最小速率（字节/秒）
    /// </summary>
    public class MinDataRate
    {
        /// <summary>
        /// Creates a new instance of <see cref="MinDataRate"/>.
        /// </summary>
        /// <param name="bytesPerSecond">The minimum rate in bytes/second at which data should be processed.</param>
        /// <param name="gracePeriod">The amount of time to delay enforcement of <paramref name="bytesPerSecond"/>,
        /// starting at the time data is first read or written.</param>
        public MinDataRate(double bytesPerSecond, TimeSpan gracePeriod)
        {
            if (bytesPerSecond <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(bytesPerSecond), "PositiveNumberOrNullMinDataRateRequired");
            }

            if (gracePeriod <= Heartbeat.Interval)
            {
                throw new ArgumentOutOfRangeException(nameof(gracePeriod), $"gracePeriod <= Heartbeat.Interval.TotalSeconds{Heartbeat.Interval.TotalSeconds}");
            }

            BytesPerSecond = bytesPerSecond;
            GracePeriod = gracePeriod;
        }

        /// <summary>
        /// The minimum rate in bytes/second at which data should be processed.
        /// </summary>
        public double BytesPerSecond { get; }

        /// <summary>
        /// The amount of time to delay enforcement of <see cref="MinDataRate" />,
        /// starting at the time data is first read or written.
        /// </summary>
        public TimeSpan GracePeriod { get; }
    }
}